1 Study Summary

The relationship between resource availability and wildlife movement patterns is pivotal to understanding species behavior and ecology. Movement response to landscape variables occurs at multiple temporal scales, from sub-diurnal to multiannual. Additionally, individuals may respond to both current and past conditions of resource availability. In this paper, we examine the temporal scale and variation of current and past resource variables that affect movement patterns of African elephants (Loxodonta africana) using sub-hourly movement data from GPS-GSM collared elephants in Etosha National Park, Namibia. We created detailed satellite-based spatiotemporal maps of vegetation biomass, as well as distance from surface water, road and fence. We used step selection functions to measure the relative importance of these landscape variables in determining elephants’ local movement patterns. We also examined how elephants respond to information, in locations they have previously visited, on productivity integrated over different temporal scales: from current to historical conditions. Our results demonstrate that elephants choose patches with higher-than average annual productivity and grass biomass, but lower tree biomass. Elephants also prefer to walk close to water, roads, and fences. These preferences vary with time of day and with season, thereby providing insights into diurnal and seasonal behavioral patterns and the ecological importance of the landscape variables examined. We also discovered that elephants respond more strongly to long-term patterns of productivity than to immediate forage conditions, in familiar locations. Our results illustrate how animals with high cognitive capacity and spatial memory integrate long-term information on landscape conditions. We illuminate the importance of long-term high temporal resolution satellite imagery to understanding the relationship between movement patterns and landscape structure.

Figure 1. Two African elephants (Loxodonta africana) in the African bush.

2 Importing Dataset

elephants <- read.csv("elephants.csv")
head(elephants)

3 Plotting Data

In order to be sure that the dataset contained no outliers, I plotted the data to interactively view the data.

ele_plot <- ggplot() + geom_point(data=elephants, 
                                   aes(utm.easting,utm.northing,
                                       color=individual.local.identifier)) +
                        labs(x="Easting", y="Northing") +
                        guides(color=guide_legend("Identifier"))

colors <- c("LA1" = "#de2d26", "LA2" = "#fc9272", "LA3" = "#fec44f")


ele_plot <- ele_plot + scale_color_manual(values = colors)

ggplotly(ele_plot)

Then, I created a function and use the lapply command to apply a function over a list or vector dataset. This took the original dataset, split it into separate files based on the individual identifier, and created new *.csv files using the identifier as the filename.

lapply(split(elephants, elephants$individual.local.identifier), 
       function(x)write.csv(x, file = paste(x$individual.local.identifier[1],".csv", sep = ""), row.names = FALSE))
Error in file(file, ifelse(append, "a", "w")) : 
  cannot open the connection

4 Simple Imagery Analysis

I used the min/max x,y data to create a bounding box to retrieve the aerial imagery, then I reprojected the imagery back to the location in Africa.

utm_points <- cbind(elephants$utm.easting, elephants$utm.northing)

utm_locations <- SpatialPoints(utm_points, 
                 proj4string=CRS("+proj=utm +zone=47 +datum=WGS84"))

proj_lat.lon <- as.data.frame(spTransform(
                utm_locations, CRS("+proj=longlat +datum=WGS84")))

colnames(proj_lat.lon) <- c("x","y")

raster <- openmap(c(max(proj_lat.lon$y)+0.01, min(proj_lat.lon$x)-0.01), 
                  c(min(proj_lat.lon$y)-0.01, max(proj_lat.lon$x)+0.01), 
                  type = "bing")

raster_utm <- openproj(raster, 
              projection = "+proj=utm +zone=47 +datum=WGS84 +units=m +no_defs")
simple <- autoplot.OpenStreetMap(raster_utm, expand = TRUE) + theme_bw() +
  theme(legend.position="bottom") +
  theme(panel.border = element_rect(colour = "black", fill=NA, size=1)) +
  geom_point(data=elephants, aes(utm.easting,utm.northing,
             color=individual.local.identifier), size = 2, alpha = 0.5) +
  theme(axis.title = element_text(face="bold")) + labs(x="Easting",
        y="Northing") + guides(color=guide_legend("Identifier"))

colors <- c("LA1" = "#de2d26", "LA2" = "#fc9272", "LA3" = "#fec44f")


simple + scale_color_manual(values = colors)

5 Home Range Analysis

5.1 Minimum Convex Polygon

MCPs are common estimators of home range, but can potentially include area not used by the animal and overestimate the home range.

#Run MCP for all individuals 
mcp_raster <- function(filename){
  data <- read.csv(file = filename)
  x <- as.data.frame(data$utm.easting)
  y <- as.data.frame(data$utm.northing)
  xy <- c(x,y)

data.proj <- SpatialPointsDataFrame(xy,data, proj4string = CRS("+proj=utm +zone=47 +datum=WGS84 +units=m +no_defs"))

  xy <- SpatialPoints(data.proj@coords)
  
  mcp.out <- mcp(xy, percent=100, unout="ha")
  
  mcp.points <- cbind((data.frame(xy)),data$individual.local.identifier)
  
  colnames(mcp.points) <- c("x","y", "identifier")
  
  mcp.poly <- fortify(mcp.out, region = "id")
  
  units <- grid.text(paste(round(mcp.out@data$area,2),"ha"), x=0.85,  y=0.95,
                     gp=gpar(fontface=4, col="white", cex=0.9), draw = FALSE)

  
  mcp.plot <- autoplot.OpenStreetMap(raster_utm, expand = TRUE) + theme_bw() + theme(legend.position="none") +
    theme(panel.border = element_rect(colour = "black", fill=NA, size=1)) +
    geom_polygon(data=mcp.poly, aes(x=mcp.poly$long, y=mcp.poly$lat), alpha=0.8) +
    geom_point(data=mcp.points, aes(x=x, y=y)) + 
    labs(x="Easting (m)", y="Northing (m)", title=mcp.points$identifier) +
    theme(legend.position="none", plot.title = element_text(face = "bold", hjust = 0.5)) + 
    annotation_custom(units)
  
  mcp.plot
}

pblapply(files, mcp_raster)

  |                                                                           | 0 % ~calculating  
  |=========================                                                  | 33% ~00s          
  |==================================================                         | 67% ~00s          
  |===========================================================================| 100% elapsed=00s  
[[1]]

[[2]]

[[3]]

5.2 Kernel-Density Estimation

A kernel uses a function to predict how likely use is for each pixel within a grid.

kde_raster <- function(filename){
  data <- read.csv(file = filename)
  x <- as.data.frame(data$utm.easting)
  y <- as.data.frame(data$utm.northing)
  xy <- c(x,y)
  
data.proj <- SpatialPointsDataFrame(xy,data, proj4string = CRS("+proj=utm +zone=47 +datum=WGS84 +units=m +no_defs"))
  xy <- SpatialPoints(data.proj@coords)
  kde<-kernelUD(xy, h="href", kern="bivnorm", grid=100)
  ver <- getverticeshr(kde, 95)
  kde.points <- cbind((data.frame(data.proj@coords)),data$individual.local.identifier)
  colnames(kde.points) <- c("x","y","identifier")
  kde.poly <- fortify(ver, region = "id")
  units <- grid.text(paste(round(ver$area,2)," ha"), x=0.85,  y=0.95,
                     gp=gpar(fontface=4, col="white", cex=0.9), draw = FALSE)
  
  kde.plot <- autoplot.OpenStreetMap(raster_utm, expand = TRUE) + theme_bw() + theme(legend.position="none") +
    theme(panel.border = element_rect(colour = "black", fill=NA, size=1)) +
    geom_polygon(data=kde.poly, aes(x=kde.poly$long, y=kde.poly$lat), alpha = 0.8) +
    geom_point(data=kde.points, aes(x=x, y=y)) +
    labs(x="Easting (m)", y="Northing (m)", title=kde.points$identifier) +
    theme(legend.position="none", plot.title = element_text(face = "bold", hjust = 0.5)) + 
    annotation_custom(units)
  kde.plot
}

pblapply(files, kde_raster)

  |                                                                           | 0 % ~calculating  
  |=========================                                                  | 33% ~01s          
  |==================================================                         | 67% ~00s          
  |===========================================================================| 100% elapsed=01s  
[[1]]

[[2]]

[[3]]

5.3 Brownian Bridge Movement

BBM incorporates temporal and behavioral characteristics of movement paths into estimation of home range.

LA1 <- read.csv("LA1.csv")

date <- as.POSIXct(strptime(as.character(LA1$timestamp),"%m/%d/%Y %H:%M", tz="Africa/Abidjan"))

LA1$date <- date

LA1.reloc <- cbind.data.frame(LA1$utm.easting, LA1$utm.northing,
                                as.vector(LA1$individual.local.identifier),
                                as.POSIXct(date))

colnames(LA1.reloc) <- c("x","y","id","date")

trajectory <- as.ltraj(LA1.reloc, date=date, id="LA1")

sig1 <- liker(trajectory, sig2 = 58, rangesig1 = c(0, 5), plotit = FALSE)

la.traj <- kernelbb(trajectory, sig1 = .7908, sig2 = 58, grid = 100)

bb_ver <- getverticeshr(la.traj, 95)

bb_poly <- fortify(bb_ver, region = "id", 
                   proj4string = CRS("+proj=utm +zone=335+
                                     datum=WGS84 +units=m +no_defs"))

colnames(bb_poly) <- c("x","y","order","hole","piece","id","group")

bb_image <- crop(la.traj, bb_ver, 
                 proj4string = CRS("+proj=utm +zone=47 +
                                   datum=WGS84 +units=m +no_defs"))

bb_units <- grid.text(paste(round(bb_ver$area,2)," ha"), x=0.85,  y=0.95,
                   gp= gpar(fontface=4, col="white", cex=0.9), draw = FALSE)

bb.plot <- autoplot.OpenStreetMap(raster_utm, expand = TRUE) + theme_bw() + theme(legend.position="none") +
  theme(panel.border = element_rect(colour = "black", fill=NA, size=1)) +
  geom_tile(data=bb_image, 
            aes(x=bb_image@coords[,1], y=bb_image@coords[,2],
            fill = bb_image@data$ud)) +
  geom_polygon(data=bb_poly, aes(x=x, y=y, group = group), color = "orange", fill = NA) +
  scale_fill_viridis_c(option = "inferno") + annotation_custom(bb_units) +
  labs(x="Easting (m)", y="Northing (m)", title="LA1") +
  theme(legend.position="none", plot.title = element_text(face = "bold", hjust = 0.5))

bb.plot

5.4 Animate Trajectory Data

la.move <- move(x=LA1$location.long, 
             y=LA1$location.lat, 
             time=as.POSIXct(LA1$timestamp, 
                             format="%m/%d/%Y %H:%M", tz="Asia/Bangkok"), 
             proj=CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"),
             data=LA1, animal=LA1$individual.local.identifier, 
             sensor=LA1$sensor.type)
movement <- align_move(la.move, res = "max", digit = 0, unit = "secs")
animate_frames(frames, fps = 5, overwrite = TRUE,
               out_file = "./moveVis-5fps.gif")
Rendering animation...
Approximated animation duration: ≈ 11.8s at 5 fps for 59 frames

  |                                                                           | 0 % ~calculating  
  |==                                                                         | 2 % ~01m 20s      
  |===                                                                        | 3 % ~01m 14s      
  |====                                                                       | 5 % ~01m 11s      
  |======                                                                     | 7 % ~01m 10s      
  |=======                                                                    | 8 % ~01m 16s      
  |========                                                                   | 10% ~01m 14s      
  |=========                                                                  | 12% ~01m 11s      
  |===========                                                                | 14% ~01m 09s      
  |============                                                               | 15% ~01m 09s      
  |=============                                                              | 17% ~01m 07s      
  |==============                                                             | 19% ~01m 05s      
  |================                                                           | 20% ~01m 03s      
  |=================                                                          | 22% ~01m 03s      
  |==================                                                         | 24% ~01m 02s      
  |====================                                                       | 25% ~01m 00s      
  |=====================                                                      | 27% ~59s          
  |======================                                                     | 29% ~57s          
  |=======================                                                    | 31% ~55s          
  |=========================                                                  | 32% ~55s          
  |==========================                                                 | 34% ~53s          
  |===========================                                                | 36% ~52s          
  |============================                                               | 37% ~50s          
  |==============================                                             | 39% ~48s          
  |===============================                                            | 41% ~47s          
  |================================                                           | 42% ~45s          
  |==================================                                         | 44% ~44s          
  |===================================                                        | 46% ~43s          
  |====================================                                       | 47% ~41s          
  |=====================================                                      | 49% ~40s          
  |=======================================                                    | 51% ~39s          
  |========================================                                   | 53% ~37s          
  |=========================================                                  | 54% ~36s          
  |==========================================                                 | 56% ~35s          
  |============================================                               | 58% ~33s          
  |=============================================                              | 59% ~32s          
  |==============================================                             | 61% ~31s          

LS0tDQp0aXRsZTogIkhvbWUgUmFuZ2UgQW5hbHlzaXMiDQphdXRob3I6ICJTYXJhaCBLcnVlZ2VyIg0KZGF0ZTogIjEwLzI5LzIwMjEiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfbm90ZWJvb2s6DQogICAgZmlnX2NhcHRpb25zOiB5ZXMgDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgcm93cy5wcmludDogMTANCiAgICB0aGVtZTogY29zbW8NCiAgICBoaWdobGlnaHQ6IGJyZWV6ZWRhcmsNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KICAgICAgc21vb3RoX3Njcm9sbDogeWVzDQplZGl0b3Jfb3B0aW9uczoNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KICBtb2RlOiBnZm0NCi0tLQ0KDQo8Ym9keSBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmM5MjcyOyI+DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIGVycm9yID0gRkFMU0UsIGluY2x1ZGUgPSBGQUxTRX0NCnBhY2thZ2VzPC1jKCJhZGVoYWJpdGF0SFIiLCJkYXRhLnRhYmxlIiwiZ2dmb3J0aWZ5IiwiZ3JpZCIsIm1vdmUiLCJtb3ZlVmlzIiwiT3BlblN0cmVldE1hcCIsImdncGxvdDIiLCAicGJhcHBseSIsInBsb3RseSIsInJnZGFsIiwic3AiLCJ0aWR5dmVyc2UiLCJ2aXJpZGlzIikNCnNhcHBseShwYWNrYWdlcywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHk9VCkNCiMgaW5zdGFsbC5wYWNrYWdlcygiT3BlblN0cmVldE1hcCIpDQojIGluc3RhbGwucGFja2FnZXMoInBiYXBwbHkiKQ0KIyBsaWJyYXJ5KHBiYXBwbHkpDQojIGluc3RhbGwucGFja2FnZXMoImFkZWhhYml0YXRIUiIpDQojIGxpYnJhcnkoYWRlaGFiaXRhdEhSKQ0KIyBsaWJyYXJ5KCJtYXB0b29scyIpDQojIGxpYnJhcnkocmdkYWwpDQojIGluc3RhbGwucGFja2FnZXMoImdwY2xpYiIpDQojIGxpYnJhcnkocGJhcHBseSkNCiMgcmVxdWlyZShwYmFwcGx5KQ0KIyBsaWJyYXJ5KGxtZTQpDQojIGxpYnJhcnkoZHBsUikNCiMgbGlicmFyeShyZWFkcikNCiMgbGlicmFyeShnZ3Bsb3QyKQ0KIyBsaWJyYXJ5KHBhdGNod29yaykNCiMgbGlicmFyeShNdU1JbikNCiMgbGlicmFyeShkcGx5cikNCiMgbGlicmFyeShnZ3Bsb3QyKQ0KIyBsaWJyYXJ5KGdyaWRFeHRyYSkNCiMgaW5zdGFsbC5wYWNrYWdlcygiUm1pc2MiKQ0KIyBsaWJyYXJ5KGdndGhlbWVzKQ0KIyBsaWJyYXJ5KG5sbWUpDQojIGluc3RhbGwucGFja2FnZXMoIlJ0b29scyIpDQojIGxpYnJhcnkocmdkYWwpDQojIGxpYnJhcnkobWFwdG9vbHMpDQojIGlmICghcmVxdWlyZShncGNsaWIpKSBpbnN0YWxsLnBhY2thZ2VzKCJncGNsaWIiLCB0eXBlPSJzb3VyY2UiKQ0KIyBncGNsaWJQZXJtaXQoKQ0KYGBgDQoNCmBgYHtyIFBhY2thZ2VzLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGUgPSBGQUxTRX0NCnBhY2thZ2VzMjwtYygiYWRlaGFiaXRhdEhSIiwiZGF0YS50YWJsZSIsImdnZm9ydGlmeSIsImdyaWQiLCJtb3ZlIiwibW92ZVZpcyIsIk9wZW5TdHJlZXRNYXAiLCJwYmFwcGx5IiwicGxvdGx5IiwicmdkYWwiLCJzcCIsInRpZHl2ZXJzZSIsInZpcmlkaXMiKQ0Kc2FwcGx5KHBhY2thZ2VzMiwgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHk9VCkNCg0KaW5zdGFsbC5wYWNrYWdlcygncGFjbWFuJykNCnBhY21hbjo6cF9sb2FkKCJnZ3NuIiwibGVhZmxldCIsIm1hcGRhdGEiLCJtYXB0b29scyIsIk9wZW5TdHJlZXRNYXAiLCJyZ2RhbCIsInRpZHl2ZXJzZSIpDQpgYGANCg0KIyBTdHVkeSBTdW1tYXJ5DQoNClRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNvdXJjZSBhdmFpbGFiaWxpdHkgYW5kIHdpbGRsaWZlIG1vdmVtZW50IHBhdHRlcm5zIGlzIHBpdm90YWwgdG8gdW5kZXJzdGFuZGluZyBzcGVjaWVzIGJlaGF2aW9yIGFuZCBlY29sb2d5LiBNb3ZlbWVudCByZXNwb25zZSB0byBsYW5kc2NhcGUgdmFyaWFibGVzIG9jY3VycyBhdCBtdWx0aXBsZSB0ZW1wb3JhbCBzY2FsZXMsIGZyb20gc3ViLWRpdXJuYWwgdG8gbXVsdGlhbm51YWwuIEFkZGl0aW9uYWxseSwgaW5kaXZpZHVhbHMgbWF5IHJlc3BvbmQgdG8gYm90aCBjdXJyZW50IGFuZCBwYXN0IGNvbmRpdGlvbnMgb2YgcmVzb3VyY2UgYXZhaWxhYmlsaXR5LiBJbiB0aGlzIHBhcGVyLCB3ZSBleGFtaW5lIHRoZSB0ZW1wb3JhbCBzY2FsZSBhbmQgdmFyaWF0aW9uIG9mIGN1cnJlbnQgYW5kIHBhc3QgcmVzb3VyY2UgdmFyaWFibGVzIHRoYXQgYWZmZWN0IG1vdmVtZW50IHBhdHRlcm5zIG9mIEFmcmljYW4gZWxlcGhhbnRzICgqTG94b2RvbnRhIGFmcmljYW5hKikgdXNpbmcgc3ViLWhvdXJseSBtb3ZlbWVudCBkYXRhIGZyb20gR1BTLUdTTSBjb2xsYXJlZCBlbGVwaGFudHMgaW4gRXRvc2hhIE5hdGlvbmFsIFBhcmssIE5hbWliaWEuIFdlIGNyZWF0ZWQgZGV0YWlsZWQgc2F0ZWxsaXRlLWJhc2VkIHNwYXRpb3RlbXBvcmFsIG1hcHMgb2YgdmVnZXRhdGlvbiBiaW9tYXNzLCBhcyB3ZWxsIGFzIGRpc3RhbmNlIGZyb20gc3VyZmFjZSB3YXRlciwgcm9hZCBhbmQgZmVuY2UuIFdlIHVzZWQgc3RlcCBzZWxlY3Rpb24gZnVuY3Rpb25zIHRvIG1lYXN1cmUgdGhlIHJlbGF0aXZlIGltcG9ydGFuY2Ugb2YgdGhlc2UgbGFuZHNjYXBlIHZhcmlhYmxlcyBpbiBkZXRlcm1pbmluZyBlbGVwaGFudHPigJkgbG9jYWwgbW92ZW1lbnQgcGF0dGVybnMuIFdlIGFsc28gZXhhbWluZWQgaG93IGVsZXBoYW50cyByZXNwb25kIHRvIGluZm9ybWF0aW9uLCBpbiBsb2NhdGlvbnMgdGhleSBoYXZlIHByZXZpb3VzbHkgdmlzaXRlZCwgb24gcHJvZHVjdGl2aXR5IGludGVncmF0ZWQgb3ZlciBkaWZmZXJlbnQgdGVtcG9yYWwgc2NhbGVzOiBmcm9tIGN1cnJlbnQgdG8gaGlzdG9yaWNhbCBjb25kaXRpb25zLiBPdXIgcmVzdWx0cyBkZW1vbnN0cmF0ZSB0aGF0IGVsZXBoYW50cyBjaG9vc2UgcGF0Y2hlcyB3aXRoIGhpZ2hlci10aGFuIGF2ZXJhZ2UgYW5udWFsIHByb2R1Y3Rpdml0eSBhbmQgZ3Jhc3MgYmlvbWFzcywgYnV0IGxvd2VyIHRyZWUgYmlvbWFzcy4gRWxlcGhhbnRzIGFsc28gcHJlZmVyIHRvIHdhbGsgY2xvc2UgdG8gd2F0ZXIsIHJvYWRzLCBhbmQgZmVuY2VzLiBUaGVzZSBwcmVmZXJlbmNlcyB2YXJ5IHdpdGggdGltZSBvZiBkYXkgYW5kIHdpdGggc2Vhc29uLCB0aGVyZWJ5IHByb3ZpZGluZyBpbnNpZ2h0cyBpbnRvIGRpdXJuYWwgYW5kIHNlYXNvbmFsIGJlaGF2aW9yYWwgcGF0dGVybnMgYW5kIHRoZSBlY29sb2dpY2FsIGltcG9ydGFuY2Ugb2YgdGhlIGxhbmRzY2FwZSB2YXJpYWJsZXMgZXhhbWluZWQuIFdlIGFsc28gZGlzY292ZXJlZCB0aGF0IGVsZXBoYW50cyByZXNwb25kIG1vcmUgc3Ryb25nbHkgdG8gbG9uZy10ZXJtIHBhdHRlcm5zIG9mIHByb2R1Y3Rpdml0eSB0aGFuIHRvIGltbWVkaWF0ZSBmb3JhZ2UgY29uZGl0aW9ucywgaW4gZmFtaWxpYXIgbG9jYXRpb25zLiBPdXIgcmVzdWx0cyBpbGx1c3RyYXRlIGhvdyBhbmltYWxzIHdpdGggaGlnaCBjb2duaXRpdmUgY2FwYWNpdHkgYW5kIHNwYXRpYWwgbWVtb3J5IGludGVncmF0ZSBsb25nLXRlcm0gaW5mb3JtYXRpb24gb24gbGFuZHNjYXBlIGNvbmRpdGlvbnMuIFdlIGlsbHVtaW5hdGUgdGhlIGltcG9ydGFuY2Ugb2YgbG9uZy10ZXJtIGhpZ2ggdGVtcG9yYWwgcmVzb2x1dGlvbiBzYXRlbGxpdGUgaW1hZ2VyeSB0byB1bmRlcnN0YW5kaW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtb3ZlbWVudCBwYXR0ZXJucyBhbmQgbGFuZHNjYXBlIHN0cnVjdHVyZS4NCg0KDQoNCiFbXShwaWNzL2VsZS5qcGcpDQo8L2NlbnRlcj4NCkZpZ3VyZSAxLiBUd28gQWZyaWNhbiBlbGVwaGFudHMgKCpMb3hvZG9udGEgYWZyaWNhbmEqKSBpbiB0aGUgQWZyaWNhbiBidXNoLg0KDQojIEltcG9ydGluZyBEYXRhc2V0IA0KDQpgYGB7cn0NCmVsZXBoYW50cyA8LSByZWFkLmNzdigiZWxlcGhhbnRzLmNzdiIpDQpoZWFkKGVsZXBoYW50cykNCmBgYA0KDQojIFBsb3R0aW5nIERhdGENCg0KSW4gb3JkZXIgdG8gYmUgc3VyZSB0aGF0IHRoZSBkYXRhc2V0IGNvbnRhaW5lZCBubyBvdXRsaWVycywgSSBwbG90dGVkIHRoZSBkYXRhIHRvIGludGVyYWN0aXZlbHkgdmlldyB0aGUgZGF0YS4NCg0KYGBge3J9DQplbGVfcGxvdCA8LSBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoZGF0YT1lbGVwaGFudHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXModXRtLmVhc3RpbmcsdXRtLm5vcnRoaW5nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9aW5kaXZpZHVhbC5sb2NhbC5pZGVudGlmaWVyKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh4PSJFYXN0aW5nIiwgeT0iTm9ydGhpbmciKSArDQogICAgICAgICAgICAgICAgICAgICAgICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKCJJZGVudGlmaWVyIikpDQoNCmNvbG9ycyA8LSBjKCJMQTEiID0gIiNkZTJkMjYiLCAiTEEyIiA9ICIjZmM5MjcyIiwgIkxBMyIgPSAiI2ZlYzQ0ZiIpDQoNCg0KZWxlX3Bsb3QgPC0gZWxlX3Bsb3QgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JzKQ0KDQpnZ3Bsb3RseShlbGVfcGxvdCkNCmBgYA0KDQpUaGVuLCBJIGNyZWF0ZWQgYSBmdW5jdGlvbiBhbmQgdXNlIHRoZSBsYXBwbHkgY29tbWFuZCB0byBhcHBseSBhIGZ1bmN0aW9uIG92ZXIgYSBsaXN0IG9yIHZlY3RvciBkYXRhc2V0LiBUaGlzIHRvb2sgdGhlIG9yaWdpbmFsIGRhdGFzZXQsIHNwbGl0IGl0IGludG8gc2VwYXJhdGUgZmlsZXMgYmFzZWQgb24gdGhlIGluZGl2aWR1YWwgaWRlbnRpZmllciwgYW5kIGNyZWF0ZWQgbmV3ICouY3N2IGZpbGVzIHVzaW5nIHRoZSBpZGVudGlmaWVyIGFzIHRoZSBmaWxlbmFtZS4NCg0KDQpgYGB7ciwgd2FybmluZyA9IEZBTFNFLCBlcnJvciA9IEZBTFNFfQ0KbGFwcGx5KHNwbGl0KGVsZXBoYW50cywgZWxlcGhhbnRzJGluZGl2aWR1YWwubG9jYWwuaWRlbnRpZmllciksIA0KICAgICAgIGZ1bmN0aW9uKHgpd3JpdGUuY3N2KHgsIGZpbGUgPSBwYXN0ZSh4JGluZGl2aWR1YWwubG9jYWwuaWRlbnRpZmllclsxXSwiLmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gRkFMU0UpKQ0KDQpmaWxlcyA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLiIsIHBhdHRlcm4gPSAiW0xBXStbMC05XSsiLCBmdWxsLm5hbWVzID0gVFJVRSkNCg0KZmlsZXMNCmBgYA0KDQojIFNpbXBsZSBJbWFnZXJ5IEFuYWx5c2lzIA0KDQpJIHVzZWQgdGhlIG1pbi9tYXggeCx5IGRhdGEgdG8gY3JlYXRlIGEgYm91bmRpbmcgYm94IHRvIHJldHJpZXZlIHRoZSBhZXJpYWwgaW1hZ2VyeSwgdGhlbiBJIHJlcHJvamVjdGVkIHRoZSBpbWFnZXJ5IGJhY2sgdG8gdGhlIGxvY2F0aW9uIGluIEFmcmljYS4NCg0KYGBge3IsIGVycm9yID0gRkFMU0UsIHdhcm5pbmc9IEZBTFNFfQ0KdXRtX3BvaW50cyA8LSBjYmluZChlbGVwaGFudHMkdXRtLmVhc3RpbmcsIGVsZXBoYW50cyR1dG0ubm9ydGhpbmcpDQoNCnV0bV9sb2NhdGlvbnMgPC0gU3BhdGlhbFBvaW50cyh1dG1fcG9pbnRzLCANCiAgICAgICAgICAgICAgICAgcHJvajRzdHJpbmc9Q1JTKCIrcHJvaj11dG0gK3pvbmU9NDcgK2RhdHVtPVdHUzg0IikpDQoNCnByb2pfbGF0LmxvbiA8LSBhcy5kYXRhLmZyYW1lKHNwVHJhbnNmb3JtKA0KICAgICAgICAgICAgICAgIHV0bV9sb2NhdGlvbnMsIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkpDQoNCmNvbG5hbWVzKHByb2pfbGF0LmxvbikgPC0gYygieCIsInkiKQ0KDQpyYXN0ZXIgPC0gb3Blbm1hcChjKG1heChwcm9qX2xhdC5sb24keSkrMC4wMSwgbWluKHByb2pfbGF0LmxvbiR4KS0wLjAxKSwgDQogICAgICAgICAgICAgICAgICBjKG1pbihwcm9qX2xhdC5sb24keSktMC4wMSwgbWF4KHByb2pfbGF0LmxvbiR4KSswLjAxKSwgDQogICAgICAgICAgICAgICAgICB0eXBlID0gImJpbmciKQ0KDQpyYXN0ZXJfdXRtIDwtIG9wZW5wcm9qKHJhc3RlciwgDQogICAgICAgICAgICAgIHByb2plY3Rpb24gPSAiK3Byb2o9dXRtICt6b25lPTQ3ICtkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyIpDQpgYGANCg0KYGBge3J9DQpzaW1wbGUgPC0gYXV0b3Bsb3QuT3BlblN0cmVldE1hcChyYXN0ZXJfdXRtLCBleHBhbmQgPSBUUlVFKSArIHRoZW1lX2J3KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsNCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIGZpbGw9TkEsIHNpemU9MSkpICsNCiAgZ2VvbV9wb2ludChkYXRhPWVsZXBoYW50cywgYWVzKHV0bS5lYXN0aW5nLHV0bS5ub3J0aGluZywNCiAgICAgICAgICAgICBjb2xvcj1pbmRpdmlkdWFsLmxvY2FsLmlkZW50aWZpZXIpLCBzaXplID0gMiwgYWxwaGEgPSAwLjUpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpICsgbGFicyh4PSJFYXN0aW5nIiwNCiAgICAgICAgeT0iTm9ydGhpbmciKSArIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQoIklkZW50aWZpZXIiKSkNCg0KY29sb3JzIDwtIGMoIkxBMSIgPSAiI2RlMmQyNiIsICJMQTIiID0gIiNmYzkyNzIiLCAiTEEzIiA9ICIjZmVjNDRmIikNCg0KDQpzaW1wbGUgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JzKQ0KYGBgDQoNCiMgSG9tZSBSYW5nZSBBbmFseXNpcyANCg0KIyMgTWluaW11bSBDb252ZXggUG9seWdvbg0KDQpNQ1BzIGFyZSBjb21tb24gZXN0aW1hdG9ycyBvZiBob21lIHJhbmdlLCBidXQgY2FuIHBvdGVudGlhbGx5IGluY2x1ZGUgYXJlYSBub3QgdXNlZCBieSB0aGUgYW5pbWFsIGFuZCBvdmVyZXN0aW1hdGUgdGhlIGhvbWUgcmFuZ2UuIA0KDQpgYGB7ciwgd2FybmluZyA9IEZBTFNFLCBlcnJvciA9IEZBTFNFfQ0KI1J1biBNQ1AgZm9yIGFsbCBpbmRpdmlkdWFscyANCm1jcF9yYXN0ZXIgPC0gZnVuY3Rpb24oZmlsZW5hbWUpew0KICBkYXRhIDwtIHJlYWQuY3N2KGZpbGUgPSBmaWxlbmFtZSkNCiAgeCA8LSBhcy5kYXRhLmZyYW1lKGRhdGEkdXRtLmVhc3RpbmcpDQogIHkgPC0gYXMuZGF0YS5mcmFtZShkYXRhJHV0bS5ub3J0aGluZykNCiAgeHkgPC0gYyh4LHkpDQoNCmRhdGEucHJvaiA8LSBTcGF0aWFsUG9pbnRzRGF0YUZyYW1lKHh5LGRhdGEsIHByb2o0c3RyaW5nID0gQ1JTKCIrcHJvaj11dG0gK3pvbmU9NDcgK2RhdHVtPVdHUzg0ICt1bml0cz1tICtub19kZWZzIikpDQoNCiAgeHkgPC0gU3BhdGlhbFBvaW50cyhkYXRhLnByb2pAY29vcmRzKQ0KICANCiAgbWNwLm91dCA8LSBtY3AoeHksIHBlcmNlbnQ9MTAwLCB1bm91dD0iaGEiKQ0KICANCiAgbWNwLnBvaW50cyA8LSBjYmluZCgoZGF0YS5mcmFtZSh4eSkpLGRhdGEkaW5kaXZpZHVhbC5sb2NhbC5pZGVudGlmaWVyKQ0KICANCiAgY29sbmFtZXMobWNwLnBvaW50cykgPC0gYygieCIsInkiLCAiaWRlbnRpZmllciIpDQogIA0KICBtY3AucG9seSA8LSBmb3J0aWZ5KG1jcC5vdXQsIHJlZ2lvbiA9ICJpZCIpDQogIA0KICB1bml0cyA8LSBncmlkLnRleHQocGFzdGUocm91bmQobWNwLm91dEBkYXRhJGFyZWEsMiksImhhIiksIHg9MC44NSwgIHk9MC45NSwNCiAgICAgICAgICAgICAgICAgICAgIGdwPWdwYXIoZm9udGZhY2U9NCwgY29sPSJ3aGl0ZSIsIGNleD0wLjkpLCBkcmF3ID0gRkFMU0UpDQoNCiAgDQogIG1jcC5wbG90IDwtIGF1dG9wbG90Lk9wZW5TdHJlZXRNYXAocmFzdGVyX3V0bSwgZXhwYW5kID0gVFJVRSkgKyB0aGVtZV9idygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKw0KICAgIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCBmaWxsPU5BLCBzaXplPTEpKSArDQogICAgZ2VvbV9wb2x5Z29uKGRhdGE9bWNwLnBvbHksIGFlcyh4PW1jcC5wb2x5JGxvbmcsIHk9bWNwLnBvbHkkbGF0KSwgYWxwaGE9MC44KSArDQogICAgZ2VvbV9wb2ludChkYXRhPW1jcC5wb2ludHMsIGFlcyh4PXgsIHk9eSkpICsgDQogICAgbGFicyh4PSJFYXN0aW5nIChtKSIsIHk9Ik5vcnRoaW5nIChtKSIsIHRpdGxlPW1jcC5wb2ludHMkaWRlbnRpZmllcikgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpKSArIA0KICAgIGFubm90YXRpb25fY3VzdG9tKHVuaXRzKQ0KICANCiAgbWNwLnBsb3QNCn0NCg0KcGJsYXBwbHkoZmlsZXMsIG1jcF9yYXN0ZXIpDQpgYGANCg0KIyMgS2VybmVsLURlbnNpdHkgRXN0aW1hdGlvbg0KDQpBIGtlcm5lbCB1c2VzIGEgZnVuY3Rpb24gdG8gcHJlZGljdCBob3cgbGlrZWx5IHVzZSBpcyBmb3IgZWFjaCBwaXhlbCB3aXRoaW4gYSBncmlkLg0KDQpgYGB7cn0NCmtkZV9yYXN0ZXIgPC0gZnVuY3Rpb24oZmlsZW5hbWUpew0KICBkYXRhIDwtIHJlYWQuY3N2KGZpbGUgPSBmaWxlbmFtZSkNCiAgeCA8LSBhcy5kYXRhLmZyYW1lKGRhdGEkdXRtLmVhc3RpbmcpDQogIHkgPC0gYXMuZGF0YS5mcmFtZShkYXRhJHV0bS5ub3J0aGluZykNCiAgeHkgPC0gYyh4LHkpDQogIA0KZGF0YS5wcm9qIDwtIFNwYXRpYWxQb2ludHNEYXRhRnJhbWUoeHksZGF0YSwgcHJvajRzdHJpbmcgPSBDUlMoIitwcm9qPXV0bSArem9uZT00NyArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMiKSkNCiAgeHkgPC0gU3BhdGlhbFBvaW50cyhkYXRhLnByb2pAY29vcmRzKQ0KICBrZGU8LWtlcm5lbFVEKHh5LCBoPSJocmVmIiwga2Vybj0iYml2bm9ybSIsIGdyaWQ9MTAwKQ0KICB2ZXIgPC0gZ2V0dmVydGljZXNocihrZGUsIDk1KQ0KICBrZGUucG9pbnRzIDwtIGNiaW5kKChkYXRhLmZyYW1lKGRhdGEucHJvakBjb29yZHMpKSxkYXRhJGluZGl2aWR1YWwubG9jYWwuaWRlbnRpZmllcikNCiAgY29sbmFtZXMoa2RlLnBvaW50cykgPC0gYygieCIsInkiLCJpZGVudGlmaWVyIikNCiAga2RlLnBvbHkgPC0gZm9ydGlmeSh2ZXIsIHJlZ2lvbiA9ICJpZCIpDQogIHVuaXRzIDwtIGdyaWQudGV4dChwYXN0ZShyb3VuZCh2ZXIkYXJlYSwyKSwiIGhhIiksIHg9MC44NSwgIHk9MC45NSwNCiAgICAgICAgICAgICAgICAgICAgIGdwPWdwYXIoZm9udGZhY2U9NCwgY29sPSJ3aGl0ZSIsIGNleD0wLjkpLCBkcmF3ID0gRkFMU0UpDQogIA0KICBrZGUucGxvdCA8LSBhdXRvcGxvdC5PcGVuU3RyZWV0TWFwKHJhc3Rlcl91dG0sIGV4cGFuZCA9IFRSVUUpICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsNCiAgICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSwgc2l6ZT0xKSkgKw0KICAgIGdlb21fcG9seWdvbihkYXRhPWtkZS5wb2x5LCBhZXMoeD1rZGUucG9seSRsb25nLCB5PWtkZS5wb2x5JGxhdCksIGFscGhhID0gMC44KSArDQogICAgZ2VvbV9wb2ludChkYXRhPWtkZS5wb2ludHMsIGFlcyh4PXgsIHk9eSkpICsNCiAgICBsYWJzKHg9IkVhc3RpbmcgKG0pIiwgeT0iTm9ydGhpbmcgKG0pIiwgdGl0bGU9a2RlLnBvaW50cyRpZGVudGlmaWVyKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSkpICsgDQogICAgYW5ub3RhdGlvbl9jdXN0b20odW5pdHMpDQogIGtkZS5wbG90DQp9DQoNCnBibGFwcGx5KGZpbGVzLCBrZGVfcmFzdGVyKQ0KYGBgDQoNCiMjICBCcm93bmlhbiBCcmlkZ2UgTW92ZW1lbnQNCg0KQkJNIGluY29ycG9yYXRlcyB0ZW1wb3JhbCBhbmQgYmVoYXZpb3JhbCBjaGFyYWN0ZXJpc3RpY3Mgb2YgbW92ZW1lbnQgcGF0aHMgaW50byBlc3RpbWF0aW9uIG9mIGhvbWUgcmFuZ2UuDQoNCmBgYHtyfQ0KTEExIDwtIHJlYWQuY3N2KCJMQTEuY3N2IikNCg0KZGF0ZSA8LSBhcy5QT1NJWGN0KHN0cnB0aW1lKGFzLmNoYXJhY3RlcihMQTEkdGltZXN0YW1wKSwiJW0vJWQvJVkgJUg6JU0iLCB0ej0iQWZyaWNhL0FiaWRqYW4iKSkNCg0KTEExJGRhdGUgPC0gZGF0ZQ0KDQpMQTEucmVsb2MgPC0gY2JpbmQuZGF0YS5mcmFtZShMQTEkdXRtLmVhc3RpbmcsIExBMSR1dG0ubm9ydGhpbmcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLnZlY3RvcihMQTEkaW5kaXZpZHVhbC5sb2NhbC5pZGVudGlmaWVyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuUE9TSVhjdChkYXRlKSkNCg0KY29sbmFtZXMoTEExLnJlbG9jKSA8LSBjKCJ4IiwieSIsImlkIiwiZGF0ZSIpDQoNCnRyYWplY3RvcnkgPC0gYXMubHRyYWooTEExLnJlbG9jLCBkYXRlPWRhdGUsIGlkPSJMQTEiKQ0KDQpzaWcxIDwtIGxpa2VyKHRyYWplY3RvcnksIHNpZzIgPSA1OCwgcmFuZ2VzaWcxID0gYygwLCA1KSwgcGxvdGl0ID0gRkFMU0UpDQoNCmxhLnRyYWogPC0ga2VybmVsYmIodHJhamVjdG9yeSwgc2lnMSA9IC43OTA4LCBzaWcyID0gNTgsIGdyaWQgPSAxMDApDQoNCmJiX3ZlciA8LSBnZXR2ZXJ0aWNlc2hyKGxhLnRyYWosIDk1KQ0KDQpiYl9wb2x5IDwtIGZvcnRpZnkoYmJfdmVyLCByZWdpb24gPSAiaWQiLCANCiAgICAgICAgICAgICAgICAgICBwcm9qNHN0cmluZyA9IENSUygiK3Byb2o9dXRtICt6b25lPTMzNSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyIpKQ0KDQpjb2xuYW1lcyhiYl9wb2x5KSA8LSBjKCJ4IiwieSIsIm9yZGVyIiwiaG9sZSIsInBpZWNlIiwiaWQiLCJncm91cCIpDQoNCmJiX2ltYWdlIDwtIGNyb3AobGEudHJhaiwgYmJfdmVyLCANCiAgICAgICAgICAgICAgICAgcHJvajRzdHJpbmcgPSBDUlMoIitwcm9qPXV0bSArem9uZT00NyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdHVtPVdHUzg0ICt1bml0cz1tICtub19kZWZzIikpDQoNCmJiX3VuaXRzIDwtIGdyaWQudGV4dChwYXN0ZShyb3VuZChiYl92ZXIkYXJlYSwyKSwiIGhhIiksIHg9MC44NSwgIHk9MC45NSwNCiAgICAgICAgICAgICAgICAgICBncD0gZ3Bhcihmb250ZmFjZT00LCBjb2w9IndoaXRlIiwgY2V4PTAuOSksIGRyYXcgPSBGQUxTRSkNCg0KYmIucGxvdCA8LSBhdXRvcGxvdC5PcGVuU3RyZWV0TWFwKHJhc3Rlcl91dG0sIGV4cGFuZCA9IFRSVUUpICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsNCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIGZpbGw9TkEsIHNpemU9MSkpICsNCiAgZ2VvbV90aWxlKGRhdGE9YmJfaW1hZ2UsIA0KICAgICAgICAgICAgYWVzKHg9YmJfaW1hZ2VAY29vcmRzWywxXSwgeT1iYl9pbWFnZUBjb29yZHNbLDJdLA0KICAgICAgICAgICAgZmlsbCA9IGJiX2ltYWdlQGRhdGEkdWQpKSArDQogIGdlb21fcG9seWdvbihkYXRhPWJiX3BvbHksIGFlcyh4PXgsIHk9eSwgZ3JvdXAgPSBncm91cCksIGNvbG9yID0gIm9yYW5nZSIsIGZpbGwgPSBOQSkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiaW5mZXJubyIpICsgYW5ub3RhdGlvbl9jdXN0b20oYmJfdW5pdHMpICsNCiAgbGFicyh4PSJFYXN0aW5nIChtKSIsIHk9Ik5vcnRoaW5nIChtKSIsIHRpdGxlPSJMQTEiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpKQ0KDQpiYi5wbG90DQpgYGANCg0KIyMgQW5pbWF0ZSBUcmFqZWN0b3J5IERhdGENCg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCmxhLm1vdmUgPC0gbW92ZSh4PUxBMSRsb2NhdGlvbi5sb25nLCANCiAgICAgICAgICAgICB5PUxBMSRsb2NhdGlvbi5sYXQsIA0KICAgICAgICAgICAgIHRpbWU9YXMuUE9TSVhjdChMQTEkdGltZXN0YW1wLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0PSIlbS8lZC8lWSAlSDolTSIsIHR6PSJBc2lhL0Jhbmdrb2siKSwgDQogICAgICAgICAgICAgcHJvaj1DUlMoIitwcm9qPWxvbmdsYXQgK2VsbHBzPVdHUzg0ICtkYXR1bT1XR1M4NCIpLA0KICAgICAgICAgICAgIGRhdGE9TEExLCBhbmltYWw9TEExJGluZGl2aWR1YWwubG9jYWwuaWRlbnRpZmllciwgDQogICAgICAgICAgICAgc2Vuc29yPUxBMSRzZW5zb3IudHlwZSkNCmBgYA0KDQpgYGB7ciwgZXJyb3IgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KbW92ZW1lbnQgPC0gYWxpZ25fbW92ZShsYS5tb3ZlLCByZXMgPSAibWF4IiwgZGlnaXQgPSAwLCB1bml0ID0gInNlY3MiKQ0KYGBgDQoNCmBgYHtyfQ0KbWVkaWFuKHRpbWVMYWcobGEubW92ZSwgdW5pdCA9ICJtaW5zIikpIA0KDQptYXBfdG9rZW4gPSAnaHR0cHM6Ly9hY2NvdW50Lm1hcGJveC5jb20vYWNjZXNzLXRva2Vucy9Ib21lLnJhbmdlLnRva2VuJw0KDQptYXBfdG9rZW4gPSAgU3lzLmdldGVudignbWFwX3Rva2VuJykgDQoNClN5cy5nZXRlbnYoJy5SZW52aXJvbicpDQoNCmdldF9tYXB0eXBlcygpDQoNCmZyYW1lcyA8LSBmcmFtZXNfc3BhdGlhbChtb3ZlbWVudCwgcGF0aF9jb2xvdXJzID0gIm9yYW5nZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgbWFwX3R5cGUgPSAic3RyZWV0cyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUpICU+JSANCiAgYWRkX2xhYmVscyh4ID0gIkxvbmdpdHVkZSIsIHkgPSAiTGF0aXR1ZGUiKSAlPiUNCiAgYWRkX25vcnRoYXJyb3coKSAlPiUgDQogIGFkZF9zY2FsZWJhcigpICU+JSANCiAgYWRkX3RpbWVzdGFtcHMobW92ZW1lbnQsIHR5cGUgPSAibGFiZWwiKSAlPiUgDQogIGFkZF9wcm9ncmVzcygpDQoNCmFuaW1hdGVfZnJhbWVzKGZyYW1lcywgZnBzID0gNSwgb3ZlcndyaXRlID0gVFJVRSwNCiAgICAgICAgICAgICAgIG91dF9maWxlID0gIi4vbW92ZVZpcy01ZnBzLmdpZiIpDQoNCmBgYA0KIVtdKC4vbW92ZVZpcy01ZnBzLmdpZiAiUmVsb2NhdGlvbiBBbmltYXRpb24iKQ0K